/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2025. All rights reserved.
 * Description: Hmfs-tools resize utils
 */

#ifndef RESIZE_UTILS_H
#define RESIZE_UTILS_H

#include <cstring>
#include <string>
#include <sys/types.h>

#include "hmfs_common.h"
#include "hmfs_io.h"
#include "hmfs_utils.h"
#include "hmfs_zoned.h"
#include "resize_data.h"
#include "securec.h"

namespace OHOS {
namespace Hmfs {
uint32_t CurrentSitAddr(std::shared_ptr<HmfsSuperBlockInfo> &superBlockInfo, uint32_t sitNumber);
void ResetCurSegment(std::shared_ptr<HmfsSuperBlockInfo> &superBlockInfo, int32_t type);
void UpdateSuperBlock(SuperBlockData *superBlock, int32_t superBlockMask);
void PrintRawSuperBlockInfo(SuperBlockData *superBlock, int32_t debugLevel, int32_t layout);
void PrintCheckpointInfo(CheckPointData *checkPoint, int32_t debugLevel, int32_t layout);
void PrintSuperBlockDataFeature(SuperBlockData *superBlockData);
void PrintSuperBlockDataErrors(SuperBlockData *superBlockData, int32_t hmfsErrors);

bool IsUsableSegment(std::shared_ptr<HmfsSuperBlockInfo> &superBlockInfo,
    uint32_t sitNumber, std::shared_ptr<HmfsConfigData> &config);
void PrintSuperBlockDataStopReason(SuperBlockData *superBlockData, int32_t forceStop);

inline bool IsCheckpointFlags(CheckPointData *checkPointData, uint32_t flag)
{
    uint32_t checkPointFlags = LE32ToNative(checkPointData->checkPointFlags);
    return checkPointFlags & flag ? true : false;
}

inline bool NeedFsyncDataRecord(std::shared_ptr<HmfsSuperBlockInfo> &superBlockInfo,
    std::shared_ptr<HmfsConfigData> &config)
{
    return !IsCheckpointFlags(superBlockInfo->checkPointData, CP_FLAG_UMOUNT) ||
        config->zonedModel == HMFS_ZONED_HM;
}

inline uint32_t EndBlockAddr(std::shared_ptr<HmfsSuperBlockInfo> &superBlockInfo)
{
    return superBlockInfo->segmentTable->mainBlockAddr +
        (LE32ToNative(superBlockInfo->rawSuper->segmentCountInMain) <<
        superBlockInfo->logBlksPerSeg);
}

inline bool HasQuotaInode(SuperBlockData *superBlock)
{
    for (int32_t i = 0; i < MAX_QUOTAS; i++) {
        if (superBlock->quotaInodeId[i]) {
            return true;
        }
    }
    return false;
}

inline void CheckSegRange(std::shared_ptr<HmfsSuperBlockInfo> &superBlockInfo, uint32_t sitNumber)
{
    uint32_t endSegno = superBlockInfo->segmentTable->segmentCount - 1;
    HMFS_ASSERT(sitNumber <= endSegno);
}

inline void GetCurrentSitPage(std::shared_ptr<HmfsSuperBlockInfo> &superBlockInfo,
    uint32_t sitNumber, SitBlockData *sitBlk)
{
    uint32_t blockAddr = CurrentSitAddr(superBlockInfo, sitNumber);
    HMFS_ASSERT(HmfsIo::GetInstance().DevReadBlock(sitBlk, blockAddr) >= 0);
}

inline SegmentEntry *GetSegEntry(std::shared_ptr<HmfsSuperBlockInfo> &superBlockInfo, uint32_t sitNumber)
{
    SitInfo *sitInfo = superBlockInfo->segmentTable->sitInfo;
    return &sitInfo->segEntries[sitNumber];
}

inline int GetDeviceIdx(std::shared_ptr<HmfsSuperBlockInfo> &superBlockInfo, uint32_t sitNumber,
    std::shared_ptr<HmfsConfigData> &config)
{
    uint32_t segStartBlkaddr = superBlockInfo->segmentTable->mainBlockAddr + sitNumber * BLOCKS_PER_SEGMENT;
    for (int i = 0; i < config->deviceNumber; i++) {
        if (config->devices[i].startBlockId <= segStartBlkaddr &&
            config->devices[i].endBlockId > segStartBlkaddr) {
            return i;
        }
    }
    return 0;
}

inline uint32_t GetZoneIdxFromDev(std::shared_ptr<HmfsSuperBlockInfo> &superBlockInfo, uint32_t sitNumber,
    uint32_t devIdx, std::shared_ptr<HmfsConfigData> &config)
{
    uint32_t segStartBlkaddr = START_BLOCK(superBlockInfo, sitNumber);
    return (segStartBlkaddr - config->devices[devIdx].startBlockId) >>
        HmfsCommon::GetInstance().LogBase2(superBlockInfo->segmentsPerSection * superBlockInfo->blocksPerSeg);
}

inline uint32_t GetFreeSegments(std::shared_ptr<HmfsSuperBlockInfo> &superBlockInfo,
    std::shared_ptr<HmfsConfigData> &config)
{
    uint32_t freeSegs = 0;
    uint32_t mainSegments = MAIN_SEGS(superBlockInfo);
    for (uint32_t i = 0; i < mainSegments; i++) {
        SegmentEntry *sitEntry = GetSegEntry(superBlockInfo, i);
        if (sitEntry->validBlocks == 0x0 && !IsCurrentSegmentNumber(superBlockInfo, i) &&
            IsUsableSegment(superBlockInfo, i, config)) {
            freeSegs++;
        }
    }
    return freeSegs;
}

inline bool isDigit(const std::string &str)
{
    for (char c : str) {
        if (!std::isdigit(c)) {
            return false;
        }
    }
    return true;
}
} // namespace Hmfs
} // namespace OHOS
#endif // RESIZE_UTILS_H